home *** CD-ROM | disk | FTP | other *** search
- /*
- * PCDISK.C
- *
- * By Eddy Carroll
- *
- * Based somewhat on RDF: by Olaf Seibert, which itself was based
- * on Matt Dillon's excellent PIPE: device.
- *
- * This handler lets you access a hard disk partition as if the
- * entire contents of the file formed a single file which can
- * be read, written to, and seeked on. This is designed mainly
- * for use with the Commodore Bridgeboard which uses an AmigaDOS
- * file to emulate a PC hard disk. By faking an AmigaDOS file
- * like this, we can avoid the inefficiency of having to go through
- * the standard file system.
- *
- * The bridgeboard actually supports two types of Amiga-mounted PC
- * partitions. Autoboot partitions are unique, and have a special
- * 512 byte header at the start giving the disk geometry. The
- * bridgeboard can boot from this. Other partitions (non-autoboot)
- * don't have the header at the start. To allow the two types to
- * be interchanged, we fake the autoboot header in the handler
- * when it's required, and never actually store it on disk at all.
- *
- * The bridgeboard assumes that PC disks are laid out according to
- * "standard" PC disk conventions, i.e. 17 sectors/track and 4 heads.
- * This is not required for the autoboot volume however, and it is
- * possible to use an Amiga-style geometry. This makes it possible
- * to share a bridgeboard partition with an AmigaDOS handler such
- * as MSDOSFileSystem which is supplied with CrossDOS, allowing
- * easy copying of files from the Amiga side.
- *
- * This handler uses the filename given when opening a file to
- * specify various items. Filenames can have any combination of
- * the following switches, though not all make sense when combined:
- *
- * /AUTO -- Include a 512 byte autoboot header at start of file
- * /AMIGA -- Use the actual Amiga sector and head info
- * /IBM -- Use the IBM settings of 4 heads, 17 sectors (default)
- * /NEW -- Only openi new files (reject open for read access)
- * /Sx -- Force x sectors per track
- * /Hx -- Force x heads per cylinder
- *
- * For example, accessing the file PCD: on its own gives a non-autoboot
- * partition and accessing PCD:AUTO/AMIGA gives an autoboot partition
- * which has the same layout on the PC as it does on the Amiga.
- *
- * In general, you need only use PCD:/AUTO for autoboot partitions and
- * PCD: for non-autoboot partitions. Any additional filename text is
- * simply ignored, unless proceeded by a '/', in which case an error
- * is returned.
- *
- * The /NEW option is intended for use with the bridgeboard JLINK
- * command to initialise a new partition for use by the Bridgeboard
- * software; the JLINK command tries to open an existing file
- * first, and if it finds one, refuses to write the new partition
- * info we need.
- *
- * The following functions are handled:
- *
- * Open() Close() OpenFileFromLock()
- * Read() Write()
- * Seek()
- * Examine()
- * Lock()
- * DupLock()
- * UnLock()
- *
- * These are more or less just dummies which appear to do something
- * useful.
- *
- * DeleteFile()
- * IsFileSystem()
- * SetComment()
- * SetDate()
- *
- * Implementation note: Since we have to be re-entrant, we don't use
- * any globals at all (except for library bases, which can be safely
- * shared). This makes some things a little clumsy, but there you go.
- */
-
- #define DEBUG 0 /* If true, full debugging msgs */
- #define SNOOP 0 /* If true, monitor read/writes */
-
- #ifndef LATTICE_50
- #include "system.h"
- #endif
-
- #if DEBUG
- #define DB(x) x
- #else
- #define DB(x)
- #endif
- #define P KPrintF
-
- #define BUFSIZE 16384 /* Buffer size for masked xfers */
- #define BOOTSIZE sizeof(BootBlock) /* Size of special Janus Boot */
-
- #define DEF_COMMENT \
- "Bridgeboard compatible DOS-style file. Copyright (c) Eddy Carroll 1992."
-
- #define IBM_HEADS 4 /* Default heads/cyl for an IBM disk */
- #define IBM_SECTORS 17 /* Default secs/track for an IBM disk */
-
- /* Various ACTIONs supported */
- /* ------------------------- */
- #define ACTION_FIND_UPDATE 1004 /* Three variations on Open() */
- #define ACTION_FIND_INPUT 1005
- #define ACTION_FIND_OUTPUT 1006
- #define ACTION_END 1007 /* Close() */
- #define ACTION_SEEK 1008 /* Seek() */
- #define ACTION_FH_FROM_LOCK 1026 /* 2.0, opens file from lock */
- #define ACTION_IS_FILESYSTEM 1027 /* Is a file system */
-
- #define ST_FILE -3 /* Indicates a normal file */
-
-
- #undef BADDR
- #define BADDR(x) ((void *)((ULONG)(x) << 2)) /* Convert BCPL->CPTR */
- #define CTOB(x) (((ULONG)(x)) >> 2) /* Convert CPTR->BADDR */
-
- #define FNAME_LEN 50 /* Maximum length of filename */
-
- #define branchto goto /* (-: Avoid goto's :-) */
-
- typedef struct DosPacket DosPacket;
- typedef struct Process Proc;
- typedef struct DeviceNode DevNode;
- typedef struct DosEnvec DosEnvec;
- typedef struct MsgPort MsgPort;
- typedef struct IOStdReq IOStdReq;
- typedef unsigned char uchar;
-
- /*
- * This is the autoboot block that appears at the start of autoboot
- * partitions used by the bridgeboard (the PC isn't directly
- * aware of this).
- */
- typedef struct BootBlock {
- uchar title[8]; /* Title, normally 'ABOOT' */
- UWORD heads; /* Heads per cylinder */
- UWORD sectors; /* Sectors per track */
- UWORD cylinders; /* Cylinders per disk */
- UWORD filler[249]; /* Pad to 512 bytes in size */
- } BootBlock;
-
-
- /*
- * This structure is used to hold details of a particular IBM
- * partition on our virtual device (block offsets are relative to
- * the start of the physical device, not our virtual device).
- */
- typedef struct IBMInfo {
- ULONG sectors; /* Number of sectors per track */
- ULONG heads; /* Number of heads per cylinder */
- ULONG numcyls; /* Number of cylinders */
- ULONG startblock; /* Starting block number */
- ULONG numblocks; /* Number of blocks */
- ULONG isautoboot; /* True if autoboot disk */
- ULONG newfileonly; /* True if only allow new files */
- } IBMInfo;
-
- /*
- * Our file structure, used to keep track of where we are etc. We
- * have an optional attachment that can be added to the end of
- * the file header, to contain a preface to the main disk file.
- * This can be used to fake an autoboot block if the PC disk is
- * an autoboot partition, and also to create "fake" files like
- * automatically generated mount-lists etc, if required. If
- * datasize is zero, no such attachment exists.
- *
- * Note that the data[1] is merely a place holder; in actual fact,
- * we allocate additional space at the end of the structure to hold
- * the full amount of data needed. To avoid confusion, we let 4
- * bytes go to waste at the end (i.e. we don't compensate for the
- * fact that we've already allocated 1 longword of the array).
- */
- typedef struct MyFile {
- ULONG start; /* Starting byte on physical device */
- ULONG offset; /* Current file offset form _Start */
- ULONG maxoffset; /* Maximum value file_Offset can be */
- ULONG datasize; /* Size of the attached data info */
- ULONG data[1]; /* Placeholder for attached data */
- } MyFile;
-
- /*
- * A standard lock structure, with the addition that we remember the
- * name used to open it, so that we can parse the options when
- * Open() is called.
- */
- typedef struct MyLock {
- struct FileLock fl; /* A standard AmigaDOS lock */
- IBMInfo ibm; /* Details about disk layout */
- } MyLock;
-
- /*
- * Transient info that needs to be passed around various functions
- * It's collected in a single structure to reduce overhead in
- * function calls.
- *
- * This is mainly used to handle the 'Mask' parameter from the
- * mountlist. Any attempts to read directly from disk into memory
- * that is not wholly within the range indicated by the mask has
- * to pass through a buffer in CHIP ram, since the device can't
- * DMA directly into the indicated memory. To avoid allocating
- * CHIP ram for this buffer needlessly on systems that have no
- * such problems, we only allocate the buffer the first time it's
- * actually needed.
- */
- typedef struct MaskData {
- long xfermask; /* Mask to check mem buffer against */
- uchar *xferbuffer; /* CHIP mem used for transfers */
- long xfersize; /* Size of above buffer */
- } MaskData;
-
-
- /*
- * Prototypes and external declarations
- */
-
- extern struct ExecBase *AbsExecBase; /* Absolute global address 4 */
- struct ExecBase *SysBase; /* Required to make Exec calls */
- struct DOSBase *DOSBase; /* Used for AmigaDOS calls */
- extern DosPacket *taskwait(); /* Wait for a message */
-
- ULONG PerformIO(MaskData *maskdata, IOStdReq *ioreq, ULONG cmd, void *buffer,
- ULONG offset, ULONG size);
- MyFile *OpenMyFile(IBMInfo *ibm, ULONG blocksize);
- int ParseFilename(uchar *filename, IBMInfo *ibm, DosEnvec *env);
- #if DEBUG
- uchar *actname();
- #endif
-
-
- /*
- * PCdisk_handler()
- *
- * Okay, here we go. This is the main entry point. We get our
- * startup message from AmigaDOS giving us info about the device
- * characteristics etc. and then go into a loop where we process
- * packet requests until eventually we are told to die.
- */
- void PCdisk_handler()
- {
- MaskData maskdata[1]; /* Pointer to memory mask info for disk i/o */
- Proc *myproc; /* Pointer to our process */
- DevNode *mynode; /* Our device node passed in parmpkt Arg3 */
- MsgPort *ioport = NULL; /* Port used for interaction with device */
- IOStdReq *ioreq = NULL; /* We use a single i/o request for all i/o */
- DosEnvec *env = NULL; /* Our Dos device environment table entry */
- uchar *default_device;/* Name of the disk device we are using */
- ULONG default_unit; /* What unit on this device */
- ULONG default_flags; /* Any necessary flags */
- ULONG opencount = 0; /* How many files & locks are open */
- ULONG blocksize; /* Size of a block in bytes */
- ULONG cylsize; /* Size of a device cylinder in bytes */
- ULONG startblock; /* Start block on our partition */
- ULONG numblocks; /* Number of blocks on our partition */
- ULONG numcyls; /* Number of cylinders on our partition */
- ULONG block_offset_mask; /* Isolate part an offset within a blk */
- ULONG block_align_mask; /* Force an offset to be block aligned */
- uchar *oneblock = NULL; /* Pointer to mem area to hold one blk */
- uchar devname[50]; /* Name of our DOS device (PCD: etc.) */
- uchar buf[50]; /* Scratch buffer */
- uchar expunge = 0; /* If true, we have been expunged */
- uchar done; /* Used for loop termination */
-
- SysBase = (struct ExecBase *)AbsExecBase; /* Get pointer to exec */
- DOSBase = OpenLibrary("dos.library", 0); /* and AmigaDOS */
- myproc = (Proc *)FindTask(0L);
-
- /*
- * The debugging uses the serial port, at current settings. Connect
- * a dumb terminal (or a modem with echo mode enabled + a comms package)
- * to see the output.
- */
- DB(P("Started debugging for custom device\n"));
-
- /*
- * Initial startup message. This is where we get our device
- * parameters from (device name, etc.)
- */
- {
- register DosPacket *mypkt;
-
- mypkt = taskwait(myproc);
- ioport = CreatePort(0, 0);
-
- if (ioport) {
- struct FileSysStartupMsg *fssm;
- uchar *dname;
-
- mynode = BADDR(mypkt->dp_Arg3);
- fssm = BADDR(mynode->dn_Startup);
- dname = BADDR(mypkt->dp_Arg1);
- if (dname) {
- strncpy(devname, dname+1, *dname);
- devname[*dname] = 0;
- } else
- devname[0] = 0;
-
- if (!fssm) {
- returnpkt(mypkt, myproc, DOSFALSE, ERROR_DEVICE_NOT_MOUNTED);
- branchto exit;
- }
-
- default_device = (uchar *)BADDR(fssm->fssm_Device) + 1;
- default_unit = fssm->fssm_Unit;
- default_flags = fssm->fssm_Flags;
- env = BADDR(fssm->fssm_Environ);
- blocksize = env->de_SizeBlock * 4;
- block_offset_mask = blocksize - 1;
- block_align_mask = ~block_offset_mask;
- numcyls = env->de_HighCyl - env->de_LowCyl + 1;
- numblocks = env->de_BlocksPerTrack *
- env->de_Surfaces * numcyls;
- cylsize = blocksize * env->de_BlocksPerTrack *
- env->de_Surfaces;
- startblock = cylsize * env->de_LowCyl;
-
- maskdata->xferbuffer = NULL;
- maskdata->xfermask = env->de_Mask;
-
- /*
- * Now try and initialise an i/o port for ourselves.
- * If we can't do it, have to fail
- */
- ioreq = CreateStdIO(ioport);
- if (!ioreq || OpenDevice(default_device, default_unit,
- ioreq, default_flags) != 0
- || (oneblock = AllocMem(blocksize, 0)) == NULL) {
- returnpkt(mypkt, myproc, DOSFALSE, ERROR_NO_FREE_STORE);
- branchto exit;
- }
- mynode->dn_Task = &myproc->pr_MsgPort;
- returnpkt(mypkt, myproc, DOSTRUE, 0);
- } else {
- returnpkt(mypkt, myproc, DOSFALSE, ERROR_NO_FREE_STORE);
- branchto exit;
- }
- DB(P("'%s', %ld flags %ld\n",
- default_device, default_unit, default_flags));
- }
-
- top:
-
- /*
- * Main loop. We sit here waiting for DOS requests and handle
- * them as best we can.
- */
- done = 0;
- while (!done) {
- register DosPacket *mypkt; /* Dos packet received */
- register MyFile *file; /* Pointer to current File */
- long type; /* Type of packet */
-
- mypkt = taskwait(myproc); /* Wait/get next packet */
- type = mypkt->dp_Type; /* Packet type */
- mypkt->dp_Res1 = DOSTRUE; /* Default return value */
- mypkt->dp_Res2 = 0; /* Default no error */
-
- /*
- * Extract File pointer. Doesn't apply to Open()
- */
- file = (MyFile *)mypkt->dp_Arg1;
-
- DB(P("%-12s arg3 %8lx, file: %8lx arg2: %8lx\n",
- actname(mypkt->dp_Type), mypkt->dp_Arg3, file, mypkt->dp_Arg2));
-
- switch (type) {
-
- case ACTION_FIND_INPUT:
- case ACTION_FIND_OUTPUT:
- case ACTION_FIND_UPDATE:
- /*
- * Handles opening any file on this device.
- */
- {
- IBMInfo ibm[1];
- uchar *name = BADDR(mypkt->dp_Arg3);
-
- /* Parse the given filename */
- if (*name)
- strncpy(buf, name + 1, *name);
- buf[*name] = '\0';
- DB(P("Open file: %s\n", buf));
-
- if (!ParseFilename(buf, ibm, env) ||
- (ibm->newfileonly && type != ACTION_FIND_OUTPUT)) {
- mypkt->dp_Res1 = DOSFALSE;
- mypkt->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
- } else {
- file = OpenMyFile(ibm, blocksize);
- if (file) {
- struct FileHandle *fh = BADDR(mypkt->dp_Arg1);
-
- memset(fh, 0, sizeof(*fh));
- fh->fh_Arg1 = (long)file;
- fh->fh_Pos = -1;
- fh->fh_End = -1;
- fh->fh_Type = &myproc->pr_MsgPort;
- opencount++;
- } else {
- mypkt->dp_Res1 = DOSFALSE;
- mypkt->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
- }
- }
- }
- returnpkt:
- returnpktplain(mypkt, myproc);
- break;
-
- case ACTION_END: /* CLOSE */
- DB(P("Close File %08lx\n", file));
- FreeMem(file, sizeof(*file));
- returnpktplain(mypkt, myproc);
- --opencount;
- break;
-
- case ACTION_READ: /* Arg2: buffer */
- { /* Arg3: size */
- uchar *buffer = (uchar *)mypkt->dp_Arg2;
- ULONG oldoffset = file->offset;
- ULONG size = mypkt->dp_Arg3;
- ULONG done = 0;
- int error = 0;
-
- DB(P("Read File %08lx ", file));
- DB(P("buffer %08lx size %08lx offset %08lx\n",
- buffer, size, file->offset));
- #if SNOOP
- P("Read : Block No. = %8lx, # Blocks = %8lx\n",
- file->offset >> 9, size >> 9);
- #endif
- /*
- * Don't read past the end of the virtual file
- */
- done = file->maxoffset - file->offset;
- if (size > done)
- size = done;
- mypkt->dp_Res1 = size;
-
- /*
- * Handle reads from the bootblock if this is
- * an autoboot disk. Will also be used if any other
- * kind of header is attached to the front of the
- * file (such as a mountlist entry, for example.)
- */
- if (size && file->offset < file->datasize) {
- ULONG bsize = MIN(size, file->datasize - file->offset);
- uchar *header = (uchar *)file->data;
-
- memcpy(buffer, header + file->offset, bsize);
- file->offset += bsize;
- size -= bsize;
- buffer += bsize;
- }
- if (size && (file->offset & block_offset_mask)) {
- /*
- * We want all disk i/o via scsi.device to be
- * on sector boundaries, to prevent scsi.device
- * getting confused. So, if we are not aligned
- * on a sector, we read the whole sector anyway,
- * then just copy what we need.
- */
- ULONG blkoffset = file->offset & block_align_mask;
- ULONG byteoffset = file->offset & block_offset_mask;
- ULONG numbytes = MIN(blocksize - byteoffset, size);
-
- DB(P("Read: first sectors, offset = %8ld, num = %8ld\n",
- file->offset, numbytes));
- error |= PerformIO(maskdata, ioreq, CMD_READ, oneblock,
- file->start + blkoffset, blocksize);
- memcpy(buffer, oneblock + file->offset-blkoffset, numbytes);
- file->offset += numbytes;
- buffer += numbytes;
- size -= numbytes;
- }
- /*
- * Now we're sector-aligned. Read in as many full
- * blocks as possible. (This is by far the most
- * common case, since almost all of our requests will
- * come from the bridgeboard software, which always
- * looks for data on sector boundaries.
- */
- if (size >= blocksize) {
- ULONG numbytes = size & block_align_mask;
-
- DB(P("Read: full sectors, offset = %8ld, num = %8ld\n",
- file->offset, numbytes));
- error |= PerformIO(maskdata, ioreq, CMD_READ, buffer,
- file->start + file->offset, numbytes);
- file->offset += numbytes;
- buffer += numbytes;
- size -= numbytes;
- }
- /*
- * Now check for any partial read from the final
- * sector. As above, we handle this by reading the
- * entire sector into a local buffer, then copying
- * the required data into the caller's buffer.
- */
- if (size) {
- DB(P("Read: last sector, offset = %8ld, num = %8ld\n",
- file->offset, size));
- error |= PerformIO(maskdata, ioreq, CMD_READ, oneblock,
- file->start + file->offset, blocksize);
- memcpy(buffer, oneblock, size);
- file->offset += size;
- buffer += size;
- size = 0;
- }
- /*
- * Now check did an error occur at any stage
- */
- if (error) {
- mypkt->dp_Res1 = -1;
- mypkt->dp_Res2 = ERROR_READ_PROTECTED; /* Seems best */
- file->offset = oldoffset;
- }
- }
- branchto returnpkt;
-
- case ACTION_WRITE: /* Arg2: buffer */
- { /* Arg3: size */
- uchar *buffer = (uchar *)mypkt->dp_Arg2;
- ULONG oldoffset = file->offset;
- ULONG size = mypkt->dp_Arg3;
- ULONG done = 0;
- int error = 0;
-
- DB(P("Write: File = %8lx ", file));
- DB(P("buffer %08lx size %08lx offset %08lx\n",
- buffer, size, file->offset));
- #if SNOOP
- P("Write: Block No. = %8lx, # Blocks = %8lx\n",
- file->offset >> 9, size >> 9);
- #endif
- /*
- * Don't write past the end of the virtual file
- */
- done = file->maxoffset - file->offset;
- if (size > done)
- size = done;
- mypkt->dp_Res1 = size;
-
- /*
- * Handle writes to the header of the file, if any.
- * We do this by just plain ignoring such writes,
- * since they aren't stored permanently anyway.
- */
- if (size && file->offset < file->datasize) {
- ULONG bsize = MIN(size, file->datasize - file->offset);
-
- file->offset += bsize;
- size -= bsize;
- buffer += bsize;
- }
- if (size && (file->offset & block_offset_mask)) {
- /*
- * We want all disk i/o via scsi.device to be
- * on sector boundaries, to prevent scsi.device
- * getting confused. So, if we are not aligned
- * on a sector, we read the whole sector, modify
- * what's necessary, then write it again.
- */
- ULONG blkoffset = file->offset & block_align_mask;
- ULONG byteoffset = file->offset & block_offset_mask;
- ULONG numbytes = MIN(blocksize - byteoffset, size);
-
- DB(P("Write: first sectors, offset = %8ld, num = %8ld\n",
- file->offset, numbytes));
- error |= PerformIO(maskdata, ioreq, CMD_READ, oneblock,
- file->start + blkoffset, blocksize);
- memcpy(oneblock + file->offset-blkoffset, buffer, numbytes);
- if (!error) {
- error |= PerformIO(maskdata, ioreq, CMD_WRITE,
- oneblock, file->start + blkoffset, blocksize);
- }
- file->offset += numbytes;
- buffer += numbytes;
- size -= numbytes;
- }
- /*
- * Now we're sector-aligned. Write as many full
- * blocks as possible. (This is by far the most
- * common case, since almost all of our requests will
- * come from the bridgeboard software, which always
- * mainpulates data on sector boundaries.
- */
- if (size >= blocksize) {
- ULONG numbytes = size & block_align_mask;
-
- DB(P("Write: full sectors, offset = %8ld, num = %8ld\n",
- file->offset, numbytes));
- error |= PerformIO(maskdata, ioreq, CMD_WRITE, buffer,
- file->start + file->offset, numbytes);
- file->offset += numbytes;
- buffer += numbytes;
- size -= numbytes;
- }
- /*
- * Now check for any partial writes to the final
- * sector. As above, we handle this by reading the
- * entire sector into a local buffer, modifying the
- * desired info, then writing it back again.
- */
- if (size) {
- DB(P("Write: last sector, offset = %8ld, num = %8ld\n",
- file->offset, size));
- error |= PerformIO(maskdata, ioreq, CMD_READ, oneblock,
- file->start + file->offset, blocksize);
- memcpy(oneblock, buffer, size);
- if (!error) {
- error |= PerformIO(maskdata, ioreq, CMD_WRITE, oneblock,
- file->start + file->offset, blocksize);
- }
- file->offset += size;
- buffer += size;
- size = 0;
- }
- /*
- * Now check did an error occur at any stage
- */
- if (error) {
- mypkt->dp_Res1 = -1;
- mypkt->dp_Res2 = ERROR_WRITE_PROTECTED; /* Seems best */
- file->offset = oldoffset;
- }
- }
- branchto returnpkt;
-
- case ACTION_DIE:
- expunge = 1;
- if (opencount == 0)
- done = 1;
- branchto returnpkt;
-
- case ACTION_SEEK:
- {
- long offset = -1;
-
- switch (mypkt->dp_Arg3) { /* seek mode */
-
- case OFFSET_BEGINNING:
- offset = mypkt->dp_Arg2;
- break;
-
- case OFFSET_CURRENT:
- offset = file->offset + mypkt->dp_Arg2;
- break;
-
- case OFFSET_END:
- offset = file->maxoffset + mypkt->dp_Arg2;
- break;
- }
- if (offset >= 0 && offset <= file->maxoffset) {
- mypkt->dp_Res1 = offset;
- file->offset = offset;
- } else {
- mypkt->dp_Res1 = -1;
- mypkt->dp_Res2 = ERROR_SEEK_ERROR;
- }
- branchto returnpkt;
- }
-
- case ACTION_LOCATE_OBJECT: /* Sort of like Open() */
- {
- uchar *name = BADDR(mypkt->dp_Arg2);
- MyLock *mylock = NULL;
- IBMInfo ibm[1];
-
- /* Parse the given filename */
- if (*name)
- strncpy(buf, name + 1, *name);
- buf[*name] = '\0';
- DB(P("Lock file: %s\n", buf));
-
- if (!ParseFilename(buf, ibm, env) ||
- (ibm->newfileonly && mypkt->dp_Arg3 != ACCESS_WRITE)) {
- mypkt->dp_Res1 = DOSFALSE;
- mypkt->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
- } else if (mylock = AllocMem(sizeof (MyLock), MEMF_CLEAR)) {
- /*
- * Allocated a lock node okay, so now just copy
- * the information about the partition gleaned
- * from the filename. This can then be examined
- * by Examine() etc. if necessary.
- */
- mylock->fl.fl_Volume = CTOB(mynode);
- mylock->fl.fl_Access = mypkt->dp_Arg3;
- mylock->fl.fl_Task = &myproc->pr_MsgPort;
- mylock->ibm = *ibm;
- opencount++;
- } else {
- mypkt->dp_Res2 = ERROR_NO_FREE_STORE;
- }
- mypkt->dp_Res1 = CTOB(mylock);
- branchto returnpkt;
- }
-
- case ACTION_EXAMINE_OBJECT:
- {
- struct FileInfoBlock *fib = BADDR(mypkt->dp_Arg2);
- MyLock *mylock = BADDR(mypkt->dp_Arg1);
- IBMInfo *ibm = &mylock->ibm;
-
- fib->fib_DiskKey = ibm->startblock;
- fib->fib_DirEntryType = ST_FILE;
- strcpy(fib->fib_FileName+1, "JanusFile");
- fib->fib_FileName[0] = strlen(fib->fib_FileName+1);
- fib->fib_Protection = 0;
- fib->fib_EntryType = fib->fib_DirEntryType;
- fib->fib_Size = ibm->numblocks * blocksize;
- fib->fib_NumBlocks = ibm->numblocks;
- DateStamp(&fib->fib_Date); /* Use current time */
- strcpy(fib->fib_Comment+1, DEF_COMMENT);
- fib->fib_Comment[0] = strlen(fib->fib_Comment+1);
- branchto returnpkt;
- }
-
- case ACTION_EXAMINE_NEXT:
- mypkt->dp_Res1 = DOSFALSE;
- mypkt->dp_Res2 = ERROR_NO_MORE_ENTRIES;
- branchto returnpkt;
-
- case ACTION_COPY_DIR:
- {
- MyLock *mylock = NULL;
-
- if (mylock = AllocMem(sizeof (MyLock), MEMF_CLEAR)) {
- *mylock = *(MyLock *)BADDR(mypkt->dp_Arg1);
- opencount++;
- } else {
- mypkt->dp_Res2 = ERROR_NO_FREE_STORE;
- }
- mypkt->dp_Res1 = CTOB(mylock);
- branchto returnpkt;
- }
-
- case ACTION_FREE_LOCK:
- {
- if (mypkt->dp_Arg1) {
- FreeMem(BADDR(mypkt->dp_Arg1), sizeof(MyLock));
- opencount--;
- }
- branchto returnpkt;
- }
-
- case ACTION_FH_FROM_LOCK:
- {
- /*
- * The lock we're passed in has already been initialised
- * with the appropriate disk info, so we just pretty
- * much duplicate the Open() code here to create and
- * initialise the file handle based on this.
- * opening. This 'hack' only works because we are
- * not interpreting the filename in any particular way.
- */
- MyLock *mylock = BADDR(mypkt->dp_Arg2);
-
- file = OpenMyFile(&mylock->ibm, blocksize);
- if (file) {
- struct FileHandle *fh = BADDR(mypkt->dp_Arg1);
-
- memset(fh, 0, sizeof(*fh));
- fh->fh_Arg1 = (long)file;
- fh->fh_Pos = -1;
- fh->fh_End = -1;
- fh->fh_Type = &myproc->pr_MsgPort;
- FreeMem(mylock, sizeof (MyLock));
- } else {
- mypkt->dp_Res1 = DOSFALSE;
- mypkt->dp_Res2 = ERROR_NO_FREE_STORE;
- }
- branchto returnpkt;
- }
-
- case ACTION_PARENT:
- mypkt->dp_Res1 = 0;
- mypkt->dp_Res2 = ERROR_DIR_NOT_FOUND;
- branchto returnpkt;
-
- case ACTION_DISK_INFO:
- case ACTION_INFO:
- {
- struct InfoData *info;
-
- if (type == ACTION_DISK_INFO)
- info = BADDR(mypkt->dp_Arg1);
- else /* ACTION_INFO */
- info = BADDR(mypkt->dp_Arg2);
-
- info->id_NumSoftErrors = 0;
- info->id_UnitNumber = default_unit;
- info->id_DiskState = ID_VALIDATED;
- info->id_NumBlocks = numblocks;
- info->id_NumBlocksUsed = numblocks;
- info->id_BytesPerBlock = env->de_SizeBlock * 4;
- info->id_DiskType = ID_DOS_DISK;
- info->id_VolumeNode = CTOB(mynode);
- info->id_InUse = 1;
- branchto returnpkt;
- }
-
- case ACTION_CURRENT_VOLUME:
- mypkt->dp_Res1 = CTOB(mynode);
- branchto returnpkt;
-
- case ACTION_IS_FILESYSTEM:
- case ACTION_SET_PROTECT:
- case ACTION_SET_COMMENT:
- case ACTION_SET_DATE:
- case ACTION_INHIBIT:
- case ACTION_FLUSH:
- /*
- * We make these into NOP's rather than letting them fail,
- * to stop application programs from getting worried.
- */
- branchto returnpkt;
-
- default:
- returnpkt(mypkt, myproc, DOSFALSE, ERROR_ACTION_NOT_KNOWN);
- break;
- } /* end switch */
-
- DB(P(" Res1 %08lx Res2 %08lx\n",
- mypkt->dp_Res1, mypkt->dp_Res2));
- } /* end while (done) */
-
- /*
- * Can only exit if no messages pending. There might be a window
- * here, but there is nothing that can be done about it.
- */
-
- #if DEBUG
- if (!expunge)
- branchto top;
- #endif
-
- Forbid();
- if (taskpktrdy(myproc)) {
- Permit();
- branchto top;
- }
-
- mynode->dn_Task = NULL;
- Permit();
-
- exit:
- if (ioreq->io_Device) CloseDevice(ioreq);
- if (ioreq) DeleteStdIO(ioreq);
- if (ioport) DeletePort(ioport);
- if (oneblock) FreeMem(oneblock, blocksize);
-
- if (maskdata->xferbuffer) {
- FreeMem(maskdata->xferbuffer, maskdata->xfersize);
- maskdata->xferbuffer = NULL;
- }
-
- DB(P("Exiting from device.\n"));
-
- /* We are a process "so we fall off the end of the world" */
-
- if (expunge) {
- BPTR mycode = mynode->dn_SegList;
-
- Forbid();
- mynode->dn_SegList = NULL;
- UnLoadSeg(mycode);
- /* We execute in unallocated memory now... and Forbid()den. */
- }
- CloseLibrary(DOSBase);
-
- /* MUST fall through */
- }
-
- /*
- * PerformIO(maskdata, ioreq, cmd, buffer, offset, size)
- *
- * Carries out specified IO as per parameters and returns when
- * complete. Maskdata is used to check for disk i/o which doesn't
- * fall within the scope of the supplied buffer. Such i/o is
- * handled by passing it through an intermediary buffer first,
- * then copying it by hand to the required destination.
- *
- * Note that offset and size must be multiples of the device's
- * blocksize, or the device (especially scsi.device) may lock up.
- *
- * Returns -1 if an error occurred.
- */
- ULONG PerformIO(MaskData *maskdata, IOStdReq *ioreq, ULONG cmd, void *buffer,
- ULONG offset, ULONG size)
- {
- DB(P("PerfIO buffer %08lx size %08lx offset %08lx\n",
- buffer, size, offset));
- ioreq->io_Command = cmd;
- ioreq->io_Length = size;
- ioreq->io_Data = buffer;
- ioreq->io_Offset = offset;
- DoIO(ioreq);
- if (ioreq->io_Actual != size || ioreq->io_Error)
- return (-1);
- else
- return (0);
- }
-
- /*
- * ParseFilename(filename, ibminfo, diskenv)
- *
- * This function parses the specified filename and fills in the
- * ibminfo structure with details of the geometry of the disk as
- * it should appear to the PC. Defaults are taken from diskenv as
- * necessary.
- *
- * We can fairly easily calculate the IBM sector and head values.
- * We manipulate the starting block info a bit, however, to
- * arrange that the IBM partition data starts an integral number
- * of cylinders from the start of the physical disk. This is not
- * strictly required (after all, the bridgeboard software is
- * accessing the whole thing as a file anyway and couldn't care
- * less) but it helps filesystems like the MSDOSFileSystem in
- * CrossDOS which expect such things. It costs us a tiny amount
- * of usable disk space, but not enough to worry about.
- *
- * The filename itself can have a number of options, as detailed
- * at the start of this source code. If the filename doesn't
- * make sense, a zero is returned, else non-zero.
- */
- int ParseFilename(uchar *filename, IBMInfo *ibm, DosEnvec *env)
- {
- char *p;
- long startblock;
- long numblocks;
- long icylsize;
-
- ibm->heads = 0;
- ibm->sectors = 0;
- ibm->isautoboot = 0;
- ibm->newfileonly = 0;
-
- p = filename;
- while (*p) {
- if (*p == '/') {
- p++;
- if (strnicmp(p, "AMIGA", 5) == 0) {
- ibm->heads = env->de_Surfaces;
- ibm->sectors = env->de_BlocksPerTrack;
- p += 5;
- } else if (strnicmp(p, "IBM", 3) == 0) {
- ibm->heads = IBM_HEADS;
- ibm->sectors = IBM_SECTORS;
- p += 3;
- } else if (strnicmp(p, "AUTO", 4) == 0) {
- ibm->isautoboot = 1;
- p += 4;
- } else if (strnicmp(p, "NEW", 3) == 0) {
- ibm->newfileonly = 1;
- p += 3;
- } else if (*p == 's' || *p == 'S') {
- ibm->sectors = atoi(++p);
- while (*p && *p != '/')
- p++;
- } else if (*p == 'h' || *p == 'H') {
- ibm->heads = atoi(++p);
- while (*p && *p != '/')
- p++;
- } else
- return (0);
- } else
- *p++;
- }
- if (ibm->heads == 0) ibm->heads = IBM_HEADS;
- if (ibm->sectors == 0) ibm->sectors = IBM_SECTORS;
-
- icylsize = ibm->heads * ibm->sectors;
- startblock = env->de_LowCyl * env->de_Surfaces * env->de_BlocksPerTrack;
- numblocks = env->de_BlocksPerTrack * env->de_Surfaces *
- (env->de_HighCyl - env->de_LowCyl + 1);
-
- ibm->startblock = ((startblock + icylsize - 1) / icylsize) * icylsize;
- ibm->numcyls = (numblocks - (ibm->startblock - startblock)) / icylsize;
- ibm->numblocks = ibm->numcyls * icylsize;
- return (1);
- }
-
- /*
- * OpenMyFile(IBMInfo *ibm, blocksize)
- *
- * Attempts to create and initialise a MyFile structure suitable
- * for accessing the section of the disk defined in ibm. This
- * includes creating a fake Janus bootblock, just in case it's
- * needed. Returns a pointer to the file structure if successfull,
- * or NULL if not enough memory.
- *
- * Blocksize is the physical size of a block on the disk.
- */
- MyFile *OpenMyFile(IBMInfo *ibm, ULONG blocksize)
- {
- MyFile *file;
- BootBlock *bb;
- ULONG headersize = 0;
-
- if (ibm->isautoboot)
- headersize = sizeof(BootBlock);
-
- file = (MyFile *)AllocMem(sizeof(MyFile) + headersize, MEMF_CLEAR);
- if (!file)
- return (NULL);
-
- file->start = ibm->startblock * blocksize;
- file->offset = 0;
- file->maxoffset = ibm->numblocks * blocksize;
- file->datasize = headersize;
-
- if (ibm->isautoboot) {
- file->maxoffset += headersize;
- file->start -= headersize;
- bb = (BootBlock *)file->data;
- strcpy(bb->title, "ABOOT");
- bb->heads = ibm->heads;
- bb->sectors = ibm->sectors;
- bb->cylinders = ibm->numcyls;
- }
- return (file);
- }
-
- #if DEBUG
- /*
- * Translates action numbers to action names to ease debugging
- */
- uchar *actname(int actnum)
- {
- switch (actnum) {
- case ACTION_FIND_INPUT: return ("FIND_INPUT");
- case ACTION_FIND_OUTPUT: return ("FIND_OUTPUT");
- case ACTION_FIND_UPDATE: return ("FIND_UPDATE");
- case ACTION_END: return ("END");
- case ACTION_READ: return ("READ");
- case ACTION_WRITE: return ("WRITE");
- case ACTION_DIE: return ("DIE");
- case ACTION_SEEK: return ("SEEK");
- case ACTION_LOCATE_OBJECT: return ("LOCATE_OBJ");
- case ACTION_EXAMINE_OBJECT: return ("EXAMINE_OBJ");
- case ACTION_EXAMINE_NEXT: return ("EXAMINE_NEXT");
- case ACTION_COPY_DIR: return ("COPY_DIR");
- case ACTION_FREE_LOCK: return ("FREE_LOCK");
- case ACTION_FH_FROM_LOCK: return ("FH_FROM_LOCK");
- case ACTION_PARENT: return ("PARENT");
- case ACTION_DISK_INFO: return ("DISK_INFO");
- case ACTION_INFO: return ("INFO");
- case ACTION_IS_FILESYSTEM: return ("IS_FILESYS");
- case ACTION_SET_PROTECT: return ("SET_PROTECT");
- case ACTION_SET_COMMENT: return ("SET_COMMENT");
- case ACTION_SET_DATE: return ("SET_DATE");
- case ACTION_INHIBIT: return ("INHIBIT");
- case ACTION_CURRENT_VOLUME: return ("CURRENT_VOL");
- case ACTION_FLUSH: return ("FLUSH");
- default:
- DB(P("Action_%04ld", actnum));
- return (" ");
- }
- }
- #endif
-